/**
 * Copyright (c) 2017-2024 Nop Platform. All rights reserved.
 * Author: canonical_entropy@163.com
 * Blog:   https://www.zhihu.com/people/canonical-entropy
 * Gitee:  https://gitee.com/canonical-entropy/nop-entropy
 * Github: https://github.com/entropy-cloud/nop-entropy
 */
package com.gitee.wsl.text.marker

import com.gitee.wsl.func.Function

/**
 * 描述允许附加各类标记对象的一段文本
 */
interface IMarkedString {
    /**
     * 文本对象
     *
     * @return
     */
    val text: String
        get() = textSequence.toString()

    /**
     * 内部文本对象。内部实现不一定是String，所以允许返回CharSequence。
     *
     * @return
     */
    val textSequence: CharSequence

    fun subSequence(startPos: Int, endPos: Int): CharSequence {
        return textSequence.subSequence(startPos, endPos)
    }

    /**
     * 文本长度
     */
    fun length(): Int

    /**
     * 文本是否为空
     */
    val isEmpty: Boolean

    /**
     * 文本关联的标记对象。所有标记对象的位置是不重叠的，并且按照起始位置排列
     *
     * @return
     */
    val markers: List<Marker>

    val valueMarkerCount: Int
        /**
         * 标记对象中的ValueMarker的个数
         *
         * @return
         */
        get() {
            var n = 0
            for (marker in markers) {
                if (marker is ValueMarker) n++
            }
            return n
        }

    val markerValues: List<Any?>
        get() {
            val markers = markers
            if (markers.isEmpty()) return emptyList()
            val ret = ArrayList<Any?>(markers.size)
            for (marker in markers) {
                if (marker is ValueMarker) {
                    ret.add(marker.value)
                } else if (marker is ProviderMarker) {
                    ret.add(marker.value)
                }
            }
            return ret
        }

}

/**
 * 将marker部分标记的文本替换为transformer返回的文本。
 *
 * @param transformer 根据marker生成替换文本。原文本中被marker标记的部分将被此函数的返回值替换
 * @return 对文本进行替换后生成的新文本。
 */
fun IMarkedString.renderText(transformer: Function<Marker, Any?>): String {

    if (markers.isEmpty()) return text

    val sb= StringBuilder(text.length + 32)
    var lastMarker: Marker? = null

    var i = 0
    val n = markers.size
    while (i < n) {
        val marker = markers[i]
        val str = transformer.apply(marker)
        if (str == null) {
            i++
            continue
        }
        if (lastMarker == null) {
            // first transformed marker
            sb.append(text, 0, marker.textBegin)
        } else {
            sb.append(text, lastMarker.textEnd, marker.textBegin)
        }
        sb.append(str)
        lastMarker = marker
        i++
    }

    if (lastMarker == null) {
        // first transformed marker
        sb.append(text)
    } else {
        sb.append(text, lastMarker.textEnd, text.length)
    }

    return sb.toString()
}